package com.hk.huakangcompany.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.hk.huakangcompany.mapper.AdminMapper;
import com.hk.huakangcompany.model.Admin;
import com.hk.huakangcompany.model.LoginLog;
import com.hk.huakangcompany.model.WxRole;
import com.hk.huakangcompany.model.WxUserRoleRelation;
import com.hk.huakangcompany.model.vo.LoginAdmin;
import com.hk.huakangcompany.service.AdminService;
import com.hk.huakangcompany.service.LoginLogService;
import com.hk.huakangcompany.service.WxRoleService;
import com.hk.huakangcompany.service.WxUserRoleRelationService;
import com.hk.huakangcompany.service.es.EsLoginLogService;
import com.hk.huakangcompany.utils.DateUtils;
import com.hk.huakangcompany.utils.EsUtil;
import com.hk.huakangcompany.utils.JwtTokenUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: zhe
 * @Date: 2021/6/5 18:24
 * @Statement: 管理员账户业务逻辑层
 */
@Slf4j
@Service
public class AdminServiceImpl implements AdminService {

    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private WxRoleService roleService;

    @Autowired
    private WxUserRoleRelationService userRoleRelationService;


    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    
    @Autowired
    private EsUtil esUtil;

//    登录日志服务类
    @Autowired
    private LoginLogService loginLogService;
//  Es登录日志文档
    @Autowired
    private EsLoginLogService esloginLogService;

    @Override
    public Admin findByEmailAndPassword(Admin admin) {
        Admin admin1 = adminMapper.findByEmailAndPassword(admin);
        return admin1;
    }

    @ApiOperation("jwt登录")
    @Transactional
    @Override
    public String toLogin(LoginAdmin loginAdmin, HttpServletRequest request) throws IOException {
//        登录之前先检查es是否存在该登陆日志索引库
        //        判断索引库是否需存在，不存在创建
        boolean exists = esUtil.isIndexExists(EsUtil.ES_INDEX);
        //        索引库不存在，开始创建并引入以前的登录日志
        if (!exists) {
//            创建索引库
            boolean index = esUtil.createIndex(EsUtil.ES_INDEX, EsUtil.ES_SHARDS, EsUtil.ES_REPLICAS);
            //        1、创建成功
            if (index) {
                log.error(EsUtil.ES_INDEX+"索引库创建成功！");
//           2、批量插入数据 ,读取mysql数据
                int count = loginLogService.count(-1, -1, new LoginLog());
                List<LoginLog> loginLogList = loginLogService.findAll(1,count,new LoginLog());
//            3、批量插入
                List<IndexRequest> list = new ArrayList<>(100);
                for (LoginLog log : loginLogList) {
                    IndexRequest indexRequest = new IndexRequest(EsUtil.ES_INDEX);
//            _id
                    indexRequest.id(log.getId().toString());
                    indexRequest.source(JSON.toJSONString(log), XContentType.JSON);
                    list.add(indexRequest);
                }
                log.error("开始批量插入...");
                boolean b = esUtil.bulkCreateDocument(10l, list);
//            批量插入成功 true 失败 false成功
                if (!b) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log.error("批量插入成功.....");
                }
            }
        }
        String username = loginAdmin.getUsername();
        Assert.notNull(username,"账号必须不能为空");
        String password = loginAdmin.getPassword();
        Assert.notNull(password,"密码必须不能为空");
        LoginAdmin loginAdmin1 = queryByEmail(username);
//        获取到的密码，加密了就不需要再次加密
        boolean matches = passwordEncoder.matches(password, loginAdmin1.getPassword());
        if(matches){
            //      保存登录日志 status:状态：0：使用中 1：已下线 主键回显
            String loginIp = request.getRemoteAddr();
            LoginLog loginLog = LoginLog.builder()
                    .loginId(loginAdmin1.getId())
                    .loginName(loginAdmin1.getName())
                    .email(loginAdmin1.getEmail())
                    .loginIp(loginIp)
                    .state(0)
                    .build();
            loginLogService.save(loginLog);
//            保证数据库的数据成功后再进行其他操作
            if (loginLog.getId() > 0) {
                //            存储到Es中
                esloginLogService.createDocument(EsUtil.ES_INDEX,loginLog,String.valueOf(loginLog.getId()),1l);
            }
            loginAdmin1.setLoginLogId(loginLog.getId());
            return jwtTokenUtil.generateToken(loginAdmin1);
        }
        return null;
    }

    @Override
    public int findByEmail(String email) {
        Admin admin = adminMapper.findByEmail(email);
        if (admin != null ) {
            log.error("邮箱已存在，请更换邮箱！");
            return 1;
        }
        return 0;
    }

    @Override
    public LoginAdmin queryByEmail(String email) {
        Admin admin = adminMapper.findByEmail(email);
        LoginAdmin loginAdmin = LoginAdmin.builder().id(admin.getId())
                .name(admin.getName())
                .email(admin.getEmail())
                .password(admin.getPassword())
                .build();
        return loginAdmin;
    }

    /**
     * 1、获取所有管理员信息（不包含登录管理员和系统管理员）
     * 2、获取所有角色信息
     * 3、通过管理员ID查询用户角色中间表返回角色ID集合
     * 4、通过角色Id集合获取到角色Name集合
     * 5、将角色Name集合去掉【】转化为String，赋值给rName
     * @param page
     * @param limit
     * @param t
     * @return
     */
    @Override
    public List<Admin> findAll(Integer page, Integer limit, Admin t) {
        PageHelper.startPage(page,limit);
//        获取所有的管理员信息（不包含登录管理员和系统管理员）
        List<Admin> adminList = adminMapper.findAll(t);
//        2、获取所有角色信息
        List<WxRole> roleList = roleService.findAll(1, 100, new WxRole());
        for (Admin admin : adminList) {
            //        3、通过管理员ID返回角色ID集合
            List<WxUserRoleRelation> userRoleRelationList = userRoleRelationService.findByAdminId(admin.getId());
//            判断当前管理员是否具有角色
            if (userRoleRelationList.isEmpty()) {
                admin.setrName("暂无角色");
                continue;
            }
            List<Integer> roleIds = userRoleRelationList.stream().map(WxUserRoleRelation::getRoleId).collect(Collectors.toList());
//        4、通过角色Id集合获取到角色Name集合
            List<WxRole> wxRoleList = roleService.findByIds(roleIds);
            List<String> rNames = wxRoleList.stream().map(WxRole::getName).collect(Collectors.toList());
            String rName = rNames.toString().replace("[", "").replace("]", "");
            admin.setrName(rName);
        }
        return adminList;
    }

    @Override
    public int count(Integer page, Integer limit, Admin t) {
        int count = adminMapper.count(t);
        return count;
    }

    @Override
    public Admin findById(Integer id) {
        Admin admin = adminMapper.findById(id);
        return admin;
    }

    @ApiOperation("注册管理员逻辑")
    @Override
    public int save(Admin admin) {
//      密码加密
        String password = passwordEncoder.encode(admin.getPassword());
        admin.setPassword(password);
        //        修改日期时间
        String dateTimeString = DateUtils.dateTimeString(new Date());
        admin.setGmtCreate(dateTimeString);
        admin.setGmtModified(dateTimeString);
        int save = adminMapper.save(admin);
        return save;
//        return 0;
    }

    @Override
    public int update(Admin admin) {
        //        修改日期时间
        String dateTimeString = DateUtils.dateTimeString(new Date());
        admin.setGmtModified(dateTimeString);
        int update = adminMapper.update(admin);
        if (update == 1) {
            log.error("当前管理员信息修改成功");
        }
        return update;
    }

    @Override
    public int updatePassWord(Admin admin) {
        //        修改日期时间
        String dateTimeString = DateUtils.dateTimeString(new Date());
        admin.setGmtModified(dateTimeString);
        int updatePassWord = adminMapper.updatePassWord(admin);
        if (updatePassWord == 1) {
            log.error("当前管理员密码修改成功");
        }
        return updatePassWord;
    }

    /**
     * 1、通过管理员Id检查是否具有所属角色
     * 2、有角色，则将关联中间表记录数先删除，无 则进行下一步
     * 3、通过管理员Id删除管理官即可
     * @param id
     * @return
     */
    @Transactional
    @Override
    public int delete(Integer id) {
        List<WxUserRoleRelation> userRoleRelationList = userRoleRelationService.findByAdminId(id);
//        判断是否具有所属角色
        if (userRoleRelationList.isEmpty()) {
            int delete = adminMapper.delete(id);
            if (delete == 1 ) {
                log.error("当前ID为"+id+"的管理员删除成功");
            }
            return delete;
        }
//        2、通过管理员Id删除管理员-角色关系记录
        userRoleRelationService.deleteByAdminId(id);
//        删除管理员
        int delete = adminMapper.delete(id);
        if (delete == 1 ) {
            log.error("当前ID为"+id+"的管理员删除成功");
        }
        return delete;

    }
}
